﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace per.esmool.utils {

    public static class TypeKit {

        public static T ChangeType<T>(object value) {
            var r = ChangeType(typeof(T), value);
            if (r is null)
                return default;
            return (T)r;
        }

        public static object ChangeType(Type destType, object value) {
            if (value is null)
                return value;
            if (value is DBNull)
                return null;

            Type primaryType = GetNullablePrimaryType(destType);
            return primaryType is null ?
                Convert.ChangeType(value, destType) :
                Convert.ChangeType(value, primaryType);
        }

        public static Type GetNullablePrimaryType(Type type) {
            if (!type.IsValueType)
                return null;

            if (!type.IsGenericType)
                return null;

            var definition = type.GetGenericTypeDefinition();
            if (definition is null || definition != typeof(Nullable<>))
                return null;

            var arguments = type.GetGenericArguments();
            var arugmentType = arguments.FirstOrDefault();
            return arugmentType;
        }

        public static new bool Equals(object a, object b) {
            if (a is null && b is null)
                return true;
            if (a is null || b is null)
                return false;
            return a.Equals(b);
        }

        public static Type GetType(string typeFullName, string assemblyName) {
            var list = FilterAssemblies(assemblyName);
            foreach (var assembly in list) {
                var type = assembly.GetType(typeFullName);
                if (type is null)
                    continue;
                return type;
            }
            return null;
        }

        static IEnumerable<System.Reflection.Assembly> FilterAssemblies(string assemblyName) {
            System.Reflection.Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            if (assemblyName is null)
                return assemblies;

            var list = new List<System.Reflection.Assembly>();
            foreach (var assembly in assemblies) {
                var assName = assembly.GetName();
                var name = assName.Name;
                var fullName = assName.FullName;
                if (name != assemblyName && fullName != assemblyName)
                    continue;
                list.Add(assembly);
            }
            return list;
        }

    }
}
